home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 7
/
Apprentice-Release7.iso
/
Source Code
/
Pascal
/
Code Resources
/
Eclectic CDEFs
/
CDEFTester Folder
/
MovableModal.p
< prev
Wrap
Text File
|
1997-02-27
|
13KB
|
445 lines
{ MovableModal: This unit implements a MovableModalDialog routine similar to the Toolbox routine ModalDialog }
{ to be used for movable modal dialogs }
{}
{ ANTI© 1993 Merzwaren, modified by Sebastiano Pilla 1996 }
{ <mailto:case@tvol.it> }
unit MovableModal;
interface
uses
Dialogs;
procedure DisableMenuBar (inEditMenuID: SInt16;
inHmnuID: SInt16);
procedure ReEnableMenuBar;
procedure MovableModalDialog (inFilterUPP: ModalFilterUPP;
var ioItemHit: SInt16);
implementation
uses
Balloons, LowMem;
const
kSystemMenuThreshold = -16000; { menu IDs <= than this are used by the system }
kMovableModalEventMask = mDownMask + mUpMask + keyDownMask + keyUpMask + autoKeyMask + updateMask + activMask + osMask;
kCutKeyEquiv = 'X';
kCopyKeyEquiv = 'C';
kPasteKeyEquiv = 'V';
type
MenuEntry = record
hMenu: MenuHandle;
leftEdge: SInt16;
end;
MenuList = record
offsetToLastMenu: SInt16;
rightmostEdge: SInt16;
unused: SInt16;
theMenus: array[0..100] of MenuEntry;
end;
MenuListPtr = ^MenuList;
MenuListH = ^MenuListPtr;
MenuBarState = record
mbsBarEnable: UInt32;
mbsEditEnable: UInt32;
mbsEditMenuID: SInt16;
mbsCutItem: SInt16;
mbsCopyItem: SInt16;
mbsPasteItem: SInt16;
end;
MenuBarStatePtr = ^MenuBarState;
MenuBarStateH = ^MenuBarStatePtr;
var
pSaveStateHdl: Handle;
{ GetMenuItemFromKeyEquiv }
{}
{ Returns the item number of the menu item with the given char }
{}
{ Entry: inMenu = handle to menu }
{ inKeyEquiv = key equivalent }
{ Exit: function result = item number requested }
function GetMenuItemFromKeyEquiv (inMenu: MenuHandle;
inKeyEquiv: Char): SInt16;
var
item, nItems: SInt16;
cmd: Char;
begin
GetMenuItemFromKeyEquiv := 0;
nItems := CountMItems(inMenu);
for item := 1 to nItems do
begin
GetItemCmd(inMenu, item, cmd);
if (Ord(cmd) = Ord(inKeyEquiv)) then
begin
GetMenuItemFromKeyEquiv := item;
Exit(GetMenuItemFromKeyEquiv);
end;
end;
end;
{ DisableMenuBar }
{}
{ Disables the entire menu bar, excluding the Edit & System menus }
{}
{ Entry: inEditMenuID = resource ID of Edit menu (or 0 if no Edit menu) }
{ inHmnuID = resource ID of valid 'hmnu' resource (or -1 if no string remapping desired) }
{ Note: Call this routine soon after putting up the movable modal, so the frontmost window is assured }
{ to be the dialog }
procedure DisableMenuBar (inEditMenuID: SInt16;
inHmnuID: SInt16);
var
menuList: MenuListH;
theMenu: MenuHandle;
menuEnable: UInt32;
theDialog: DialogPtr;
barEnable, response: SInt32;
i, nMenus, menuID: SInt16;
err: OSErr;
hasBalloons, needEditMenu: Boolean;
begin
hasBalloons := (Gestalt(gestaltHelpMgrAttr, response) = noErr) & BTST(response, gestaltHelpMgrPresent);
{ determine if the frontmost dialog contains edit fields }
theDialog := FrontWindow;
needEditMenu := (theDialog <> nil) & (DialogPeek(theDialog)^.editField >= 0);
{ get a handle to the menu list and count the menus }
menuList := MenuListH(LMGetMenuList);
nMenus := menuList^^.offsetToLastMenu div SizeOf(MenuEntry);
{ create a parameter block for saving menu bar state information }
pSaveStateHdl := NewHandleClear(SizeOf(MenuBarState));
if pSaveStateHdl <> nil then
HLock(pSaveStateHdl);
if MemError = noErr then
with MenuBarStateH(pSaveStateHdl)^^ do
begin
barEnable := 0;
{ walk the menu list }
for i := 0 to nMenus - 1 do
begin
{ get menu handle, menu ID and enable flags for this menu }
theMenu := menuList^^.theMenus[i].hMenu;
menuID := theMenu^^.menuID;
menuEnable := theMenu^^.enableFlags;
{ do nothing if this is a system menu }
if (menuID <= kSystemMenuThreshold) then
Cycle;
{ if this is the Edit menu and we need it, do some special processing }
if ((needEditMenu) and (menuID = inEditMenuID)) then
begin
{ save edit menu ID }
mbsEditMenuID := inEditMenuID;
{ save the enable flags for later restoration }
mbsEditEnable := menuEnable;
{ find which items are Cut, Copy and Paste }
mbsCutItem := GetMenuItemFromKeyEquiv(theMenu, kCutKeyEquiv);
mbsCopyItem := GetMenuItemFromKeyEquiv(theMenu, kCopyKeyEquiv);
mbsPasteItem := GetMenuItemFromKeyEquiv(theMenu, kPasteKeyEquiv);
{ enable Cut, Copy and Paste }
menuEnable := 1 + BSL(1, mbsCutItem) + BSL(1, mbsCopyItem) + BSL(1, mbsPasteItem);
theMenu^^.enableFlags := menuEnable;
Cycle;
end;
{ if this menu is enabled, disable it and set the corresponding bit in barEnable }
if (BTST(menuEnable, 0)) then
begin
barEnable := BOR(barEnable, BSL(1, i));
DisableItem(theMenu, 0);
end;
{ remap the help strings for this menu }
if (hasBalloons) then
err := HMSetMenuResID(menuID, inHmnuID);
end;
mbsBarEnable := barEnable;
end;
{ unhighlight the highlighted menu (if any) and redraw the menu bar }
HiliteMenu(0);
DrawMenuBar;
{ unlock state info parameter block }
HUnlock(pSaveStateHdl);
end;
{ ReEnableMenuBar }
{}
{ Restores the previously saved enableFlags for all menus in the menu bar }
{}
{ Note: Call this routine just after bringing down the movable modal }
procedure ReEnableMenuBar;
var
menuList: MenuListH;
response: SInt32;
theMenu: MenuHandle;
i, nMenus, menuID: SInt16;
hasBalloons: Boolean;
err: OSErr;
begin
{ sanity check: make sure pSaveStateHdl isn't NIL }
if (pSaveStateHdl = nil) then
Exit(ReEnableMenuBar);
{ determine if the Help manager is available }
hasBalloons := (Gestalt(gestaltHelpMgrAttr, response) = noErr) & BTST(response, gestaltHelpMgrPresent);
{ get a handle to the menu list and count the menus }
menuList := MenuListH(LMGetMenuList);
nMenus := menuList^^.offsetToLastMenu div SizeOf(MenuEntry);
HLock(pSaveStateHdl);
if MemError = noErr then
with MenuBarStateH(pSaveStateHdl)^^ do
begin
{ walk the menu list }
for i := 0 to nMenus - 1 do
begin
{ get menu handle and menu ID for this menu }
theMenu := menuList^^.theMenus[i].hMenu;
menuID := theMenu^^.menuID;
{ do nothing if this is a system menu }
if (menuID <= kSystemMenuThreshold) then
Cycle;
{ restore old enable state for this menu }
if (menuID = mbsEditMenuID) then
theMenu^^.enableFlags := mbsEditEnable
else if (BTST(mbsBarEnable, i)) then
EnableItem(theMenu, 0);
{ unmap the help strings for this menu }
if (hasBalloons) then
err := HMSetMenuResID(menuID, -1);
end;
end;
{ forget about the menu bar parameter block }
HUnlock(pSaveStateHdl);
if pSaveStateHdl <> nil then
DisposeHandle(pSaveStateHdl);
{ redraw the menu bar }
DrawMenuBar;
end;
{ CallBeeper }
{}
{ Calls the beeper procedure with the given sound }
{}
{ Entry: soundNo = ID of 'snd ' resource to play }
{ beeperProc = pointer to beeper proc }
procedure CallBeeper (soundNo: SInt16;
beeperProc: ProcPtr);
inline
$205F, { movea.l (sp)+, a0 }
$4E90; { jsr (a0) }
{ MovableModalMenuChoice }
{}
{ Called by the filter proc to process menu choices }
{}
{ Entry: inDialog = pointer to current dialog }
{ inEvent = ignored }
{ inMenuChoice = menu choice combination }
{ Exit: outItemHit = item number of edit field interested }
{ function result = TRUE if edit operation performed, FALSE otherwise }
function MovableModalMenuChoice (inDialog: DialogPtr;
var inEvent: EventRecord;
var outItemHit: SInt16;
inMenuChoice: SInt32): Boolean;
var
itemRect: Rect;
itemHandle: Handle;
menuID, menuItem, currentEditField, itemType: SInt16;
err: OSErr;
begin
MovableModalMenuChoice := false;
if (pSaveStateHdl = nil) then
Exit(MovableModalMenuChoice);
menuID := HiWrd(inMenuChoice);
menuItem := LoWrd(inMenuChoice);
HLock(pSaveStateHdl);
if MemError = noErr then
with MenuBarStateH(pSaveStateHdl)^^ do
begin
if (menuID = mbsEditMenuID) then
begin
{ find the current edit field }
currentEditField := DialogPeek(inDialog)^.editField + 1;
GetDialogItem(inDialog, currentEditField, itemType, itemHandle, itemRect);
{ if the current edit field is an enabled item, exit from MovableModalDialog loop }
if (BAND(itemType, kItemDisableBit) = 0) then
begin
MovableModalMenuChoice := true;
outItemHit := currentEditField;
end;
{ perform edit operation }
if (menuItem = mbsCutItem) then
begin
DialogCut(inDialog);
err := ZeroScrap;
err := TEToScrap;
end
else if (menuItem = mbsCopyItem) then
begin
DialogCopy(inDialog);
err := ZeroScrap;
err := TEToScrap;
end
else if (menuItem = mbsPasteItem) then
DialogPaste(inDialog);
end;
end;
HUnlock(pSaveStateHdl);
HiliteMenu(0);
end;
{ HandleMovableModalMouseDown }
{}
{ Handles mouse down events for the filter proc }
{}
{ Entry: inDialog = pointer to dialog }
{ ioEvent = event specification }
{ ioItemHit = item number of dialog item interested }
{ Exit: ioEvent = event spec after executing }
{ ioItemHit = item number of edit field interested }
{ function result = TRUE if the filter proc should exit, FALSE otherwise }
function HandleMovableModalMouseDown (inDialog: DialogPtr;
var ioEvent: EventRecord;
var ioItemHit: SInt16): Boolean;
var
dragRect: Rect;
wind: WindowPtr;
beeper: UniversalProcPtr;
partCode: SInt16;
begin
HandleMovableModalMouseDown := false;
{ find out where the click went down in }
partCode := FindWindow(ioEvent.where, wind);
{ if the click went in the menu bar, just call MenuSelect }
if (partCode = inMenuBar) then
begin
HandleMovableModalMouseDown := MovableModalMenuChoice(inDialog, ioEvent, ioItemHit, MenuSelect(ioEvent.where));
Exit(HandleMovableModalMouseDown);
end;
{ if the user clicked somewhere outside the dialog but in one of our windows behind, call the beeper }
if not ((partCode = inDesk) or (partCode = inSysWindow)) then
if (not PtInRgn(ioEvent.where, WindowPeek(inDialog)^.strucRgn)) then
begin
beeper := LMGetDABeeper;
if (beeper <> nil) then
CallBeeper(1, beeper);
Exit(HandleMovableModalMouseDown);
end;
{ now, we have to handle the only thing DialogSelect doesn't do for us: dragging }
if (partCode = inDrag) & (inDialog = wind) then
begin
dragRect := GetGrayRgn^^.rgnBBox;
DragWindow(wind, ioEvent.where, dragRect);
ioEvent.what := nullEvent;
end;
end;
{ MovableModalDialog }
{}
{ Substitutes ModalDialog for movable modal dialogs }
{}
{ Entry: inFilterUPP = same as modalFilter parameter for ModalDialog }
{ ioItemHit = same as itemHit parameter for ModalDialog }
{ Exit: ioItemHit = same as itemHit parameter for ModalDialog }
procedure MovableModalDialog (inFilterUPP: ModalFilterUPP;
var ioItemHit: SInt16);
var
theEvent: EventRecord;
savePort: GrafPtr;
theDialog: DialogPtr;
gotEvent: Boolean;
begin
ioItemHit := 0;
{ get a pointer to the frontmost window (which should be our movable dialog) }
theDialog := FrontWindow;
if (theDialog = nil) then
Exit(MovableModalDialog);
{ set thePort to the dialog }
GetPort(savePort);
SetPort(theDialog);
{ modal dialog event loop }
repeat
{ yield time to other processes and retrieve next event from the queue }
gotEvent := WaitNextEvent(kMovableModalEventMask, theEvent, GetCaretTime, nil);
{ the filter proc is the first one to get a chance to process the event }
if (inFilterUPP <> nil) & CallModalFilterProc(theDialog, theEvent, ioItemHit, inFilterUPP) then
Leave;
{ then comes our own processing of clicks in the menu bar and in the drag bar }
if (theEvent.what = mouseDown) & HandleMovableModalMouseDown(theDialog, theEvent, ioItemHit) then
Leave;
{ and our processing of keyboard equivalents for the Edit items }
if (theEvent.what = keyDown) & (BAND(theEvent.modifiers, cmdKey) <> 0) & MovableModalMenuChoice(theDialog, theEvent, ioItemHit, MenuKey(CHR(BAND(theEvent.message, charCodeMask)))) then
Leave;
{ finally we let the Toolbox do its own thing }
if IsDialogEvent(theEvent) & DialogSelect(theEvent, theDialog, ioItemHit) then
Leave;
until false;
{ restore the old port }
SetPort(savePort);
end;
end.